iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 7
0

現在大部分的功能都已經實作好了,剩下將資料儲存到手機,讓使用者下次開啟App時可以看到過去儲存的資料,有許多方法可以使用,由於我們的資料簡單,所以我打算使用UserDefault就好,由於我們的資料是結構體(struct),要儲存的話需要進行編碼及解碼,所以先讓ListModel遵從Codable協定,這部分在Day2建立資料模型的時候就已經實作過了:

struct ListModel:Codable {
    var title = ""
    var subtitle = ""
}

由於儲存資料模型的地方是在ListViewController內,所以我將儲存的方法也寫在這裏:

func saveData()
{
        let encoder = JSONEncoder()
        if let encodeListData = try? encoder.encode(listDatas)
        {
            UserDefaults.standard.set(encodeListData, forKey: "listData")
        }
}

上述這段程式碼的意思是,先初始化一個JSON編碼器,並且將我的listDatas編碼後,儲存進UserDefaults,儲存的key是listData,那我下次讀取時也要使用相同的key才能夠讀取到這筆資料。

儲存的方法寫完了,那要在哪裡呼叫呢??我的答案是,只要有動到資料的地方,就要儲存資料,例如新增、插入、刪除、修改。

所以我在各個動作內都呼叫這個方法,首先是新增跟插入,都是點選確認按鈕才算資料進行更動,所以我在確認按鈕內呼叫saveData(),所以你的UIAlertController內的okAction應該像這樣子:

let okAction = UIAlertAction(title: actionTitle, style: .destructive){ (action) in
            
            if let text0 = alert.textFields?[0].text, let text1 = alert.textFields?[1].text
            {
                let totalText = ListModel(title: text0, subtitle: text1)
                if alertTitle == "新增"
                {
                    self.listDatas.insert(totalText, at: 0)
                    self.toDoListTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .top)
                }
                if let indexPath = indexPath{
                    if alertTitle == "插入"
                    {
                        self.listDatas.insert(totalText, at: indexPath.row)
                        
                        self.toDoListTableView.insertRows(at: [indexPath], with: .automatic)
                    }
                }
            }
            self.saveData()
        }

另外在往左滑帶出選項時的刪除按鍵跟修改按鍵,我也是在這兩個按鍵內都呼叫saveData(),所以現在你的刪除按鍵跟修改按鍵的程式碼應該長這樣子:

 let deleteAction = UIContextualAction(style: .destructive, title: "刪除") { (action, sourceView, complete) in
              self.listDatas.remove(at: indexPath.row)
              self.toDoListTableView.deleteRows(at: [indexPath], with: .top)
              self.saveData()
              complete(true)
          }
          deleteAction.image = UIImage(systemName: "trash")
          let modifyAction = UIContextualAction(style: .normal, title: "修改") { (action, sourceView, complete) in
              let oldValue = self.listDatas[indexPath.row]
              self.indexPath = indexPath
              let destinationVC = self.storyboard?.instantiateViewController(identifier: "ModifyViewController") as! ModifyViewController
              destinationVC.listData = oldValue
              destinationVC.passingToATVCClosure = {(listData) in
                  self.listDatas[indexPath.row] = listData
                  self.saveData()
              }
              self.show(destinationVC, sender: self)
              complete(true)
          }

現在你的資料已經可以儲存到手機本地了,但是目前還缺乏讀取的實作,否則即使儲存了,下次使用者打開App,如果沒有讀取功能則依然看不到資料。

所以我們一樣在ListViewController內實作一個讀取的方法,我命名為loadData():

 func loadData()
    {
        if let loadData = UserDefaults.standard.object(forKey: "listData") as? Data
        {
            let decoder = JSONDecoder()
            if let listData = try! decoder.decode([ListModel]?.self, from: loadData)
            {
                self.listDatas = listData
                toDoListTableView.reloadData()
            }
        }
    }

上面這段程式碼是使用"listData"這個key,去讀取資料並轉型為Data,並且當我讀取到資料後,使用JSONDecoder解碼器,解碼loadData這個資料,並且解碼為[ListModel]格式,再把解完的資料,指定給我自己的listDatas,然後記得要重整表格頁面,否則表格顯示的資料不會改變。


最後我將這個loadData()方法,放在生命週期viewDidLoad()內被呼叫,所以只要每次程式一載入進來,就會重新整理資料,現在你的ListViewController內的viewDidLoad()應該長這樣子:

 override func viewDidLoad() {
        super.viewDidLoad()
        loadData()
        toDoListTableView.delegate = self
        toDoListTableView.dataSource = self
    }

現在已經完成正常功能的所有實作了,接下來屬於比較偏動畫類的...我還記得這些動畫類的實作做完後,工作室的學長們跟我說:「Jimmy,你的App怎麼這麼"虛華"」,不管!我就是爽啦!


上一篇
Day6-實作To-Do-List之修改功能(Closure傳值)、分享功能(UIActivityViewController))
下一篇
Day8-實作To-Do-List之更改表格排序及動畫(完結)
系列文
想知道自己iOS具現化系能力有多強嗎?實作幾個App就知道了30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言